<template>
  <!-- 和内置指令类似，自定义指令的参数也可以是动态的。这里指令的参数会基于组件状态，foo property响应式地更新。 -->
  <input type="text" v-focus:[foo].bar="baz" />
  <br />
  <div v-color="color">我使用来简化形式的自定义指令</div>
  <!-- 如果你的指令需要多个值，可以向它传递一个 javascript对象字面量 -->
  <div v-demo="{ color: 'green', text: 'hello!' }">对象字面量</div>
  <!-- 在组件上使用自定义指令时，它会始终应用与组件的根节点，和透传 attributes 类似。如果组件可能含有多个根节点。当应用到一个多根组件时，指令将会被忽略且抛出一个警告。和attribute不同，指令不能通过 v-bind="$attrs"来传递给一个不同的元素。总之，不推荐在组件上使用自定义指令 -->
  <!-- <Setup v-comp /> -->
</template>

<script setup>
import { ref } from 'vue'

const baz = ref('我是baz的值')
const foo = ref('foo1')
const color = ref('red')
// 在 <script setup>中，任何以 v 开头的驼峰式命名的变量都可以被用作一个自定义指令。如果不使用<script setup>，自定义指令通过directives选项注册
// 一个自定义指令被定义为一个包含类似于组件的生命周期钩子的对象。钩子接收指定绑定到的元素。
// vFocus可以在模板中以v-focus的形式使用。
const vFocus = {
  created: (el, binding) => {
    console.log('绑定元素属性前，初始化')
    // console.log(binding)
  },
  beforeMount: () => {
    console.log('元素被插入到 DOM 前调用')
  },
  mounted: (el, binding, vNode) => {
    // console.log(binding)
    // console.log(vNode)
    console.log('元素完成挂载')
    el.focus()
  },
  beforeUpdate: () => {
    console.log('更新之前')
  },
  updated: (el, binding, vNode, prevNode) => {
    console.log('更新结束')
    // console.log(binding)
    // console.log(vNode)
    // console.log(prevNode)
  },
  beforeUnmount: () => {
    console.log('卸载之前')
  },
  Unmounted: () => {
    console.log('卸载完成')
  }
}
setTimeout(() => {
  baz.value = '我被改变了'
  foo.value = 'foo2'
  color.value = 'blue'
}, 2000)

// 对于自定义指令来说，需要在 mounted 和 updated 上实现相同的行为，又并不关心其他钩子的情况很常见。可以将指令定义成一个下面这样的函数
const vColor = (el, binding) => {
  // 这会在 mounted 和 updated 时都调用
  console.log('我被调用了')
  el.style.color = binding.value
}

const vDemo = (el, binding) => {
  console.log(binding.value)
  el.style.color = binding.value.color
  el.style.background = 'yellow'
}

// 一个指令的定义对象可以提供几种钩子函数（都是可选的）
const myDirective = {
  // 在绑定元素的 attribute 前，或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {},
  // 在元素被插入到 DOM 前调用
  beforeMount() {},
  // 在绑定元素的父组件以及它自己的所有子节点都挂载完成后调用
  mounted() {},
  // 在绑定元素的父组件更新前调用
  beforeUpdate() {},
  // 在绑定元素的父组件及它自己的所有子节点都更新后调用
  updated() {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount() {},
  // 绑定元素的父组件卸载后调用
  unMounted() {}
}
</script>

<style scoped>

</style>